#include <accent/algorithms/rotate.hpp>
#include "test_base.hpp"

template <typename Traversal>
class Rotate : public ::testing::Test {};

typedef ::testing::Types<forward_traversal_tag, bidirectional_traversal_tag,
                         random_access_traversal_tag>
  traversals;
TYPED_TEST_CASE(Rotate, traversals);

TYPED_TEST(Rotate, emptyRange_rotateNoPosition_noop_noPosition) {
  ivec v;
  auto r = all_l<TypeParam>(v);
  auto p = rotate(r, r.front_position());
  // nothing happens
  ASSERT_TRUE(!p);
}

TYPED_TEST(Rotate, singleElementRange_rotateFirstPosition_noop) {
  ivec v = { 1 };
  auto r = all_l<TypeParam>(v);
  auto p = rotate(r, r.front_position());
  ASSERT_EQ((ivec{ 1 }), v);
  ASSERT_FALSE(!p);
  ASSERT_EQ(1, *p);
}

TYPED_TEST(Rotate, twoElementRange_rotateFirstPosition_noop) {
  ivec v = { 1, 2 };
  auto r = all_l<TypeParam>(v);
  auto p = rotate(r, r.front_position());
  ASSERT_EQ((ivec{ 1, 2 }), v);
  ASSERT_FALSE(!p);
  ASSERT_EQ(1, *p);
}

TYPED_TEST(Rotate, twoElementRange_rotateSecondPosition_swaps) {
  ivec v = { 1, 2 };
  auto r = all_l<TypeParam>(v);
  auto p = rotate(r, r.back_position());
  ASSERT_EQ((ivec{ 2, 1 }), v);
  ASSERT_FALSE(!p);
  ASSERT_EQ(1, *p);
}

TYPED_TEST(Rotate, threeElementRange_rotateTwo) {
  ivec v = { 1, 2, 3 };
  auto r = all_l<TypeParam>(v);
  auto p = rotate(r, r.back_position());
  ASSERT_EQ((ivec{ 3, 1, 2 }), v);
  ASSERT_FALSE(!p);
  ASSERT_EQ(1, *p);
}

TYPED_TEST(Rotate, fiveElementRange_rotateOne) {
  ivec v = { 1, 2, 3, 4, 5 };
  auto r = all_l<TypeParam>(v), s = r;
  auto p = rotate(r, s.front_position());
  ASSERT_EQ((ivec{ 1, 2, 3, 4, 5 }), v);
  ASSERT_FALSE(!p);
  ASSERT_EQ(1, *p);
}

TYPED_TEST(Rotate, fiveElementRange_rotateTwo) {
  ivec v = { 1, 2, 3, 4, 5 };
  auto r = all_l<TypeParam>(v), s = r;
  s.pop_front();
  auto p = rotate(r, s.front_position());
  ASSERT_EQ((ivec{ 2, 3, 4, 5, 1 }), v);
  ASSERT_FALSE(!p);
  ASSERT_EQ(1, *p);
}

TYPED_TEST(Rotate, fiveElementRange_rotateThree) {
  ivec v = { 1, 2, 3, 4, 5 };
  auto r = all_l<TypeParam>(v), s = r;
  s.pop_front();
  s.pop_front();
  auto p = rotate(r, s.front_position());
  ASSERT_EQ((ivec{ 3, 4, 5, 1, 2 }), v);
  ASSERT_FALSE(!p);
  ASSERT_EQ(1, *p);
}

TYPED_TEST(Rotate, fiveElementRange_rotateFour) {
  ivec v = { 1, 2, 3, 4, 5 };
  auto r = all_l<TypeParam>(v), s = r;
  s.pop_front();
  s.pop_front();
  s.pop_front();
  auto p = rotate(r, s.front_position());
  ASSERT_EQ((ivec{ 4, 5, 1, 2, 3 }), v);
  ASSERT_FALSE(!p);
  ASSERT_EQ(1, *p);
}

TYPED_TEST(Rotate, fiveElementRange_rotateFive) {
  ivec v = { 1, 2, 3, 4, 5 };
  auto r = all_l<TypeParam>(v), s = r;
  s.pop_front();
  s.pop_front();
  s.pop_front();
  s.pop_front();
  auto p = rotate(r, s.front_position());
  ASSERT_EQ((ivec{ 5, 1, 2, 3, 4 }), v);
  ASSERT_FALSE(!p);
  ASSERT_EQ(1, *p);
}
